 //
//
//		read speech data
//
//

#include "readwave.h"
#include <windows.h>

extern "C" unsigned char linear2alaw(__int16	pcm_val);
extern "C" unsigned char linear2ulaw(__int16	pcm_val);
extern "C" __int16 alaw2linear(unsigned char	a_val);
extern "C" __int16 ulaw2linear(unsigned char	u_val);

#define	ANCHOR	0//16//

FILE* OpenAFile(char *fileName, char *openType)
{
	FILE *fp;

	fp = fopen(fileName, openType);
	if (fp==NULL)
	{
		printf("can't open %s in mode %s!\n", fileName, openType);
		exit(1);
	}
	return	fp;
}

FILE* GetFileHandle(char *filename, char *mode)
{
	FILE	*fp;
	float	delay;

	if (_access(filename, 0)==-1)
	{
		printf("Error: File does not exist!(%s)!\n", filename);
		return NULL;
	}

	delay = 0;
	fp = NULL;
	while (delay < 3 && fp == NULL)
	{
		fp = fopen(filename, mode);
		if (fp != NULL)	break;
#ifdef WIN32
		Sleep(200);	// 0.2 second
#else
		sleep(1);	// 1 second
#endif
		delay += 1.0F;
	}
	if (fp == NULL)
		printf("Error: Can not access file %s!\n", filename);

	return	fp;
}

short *ReadAULawPCMWave(char *wavFile, int *numSamples, WavHead *header)
{
	FILE	*wavFp;
	short	*waveData;
	long	numRead;
	WavHead	 wavHead;
	unsigned char *aulawData;
	long	length;
	int		i;

	wavFp = GetFileHandle(wavFile, "rb");
	if (wavFp==NULL)
	{
		printf("can't open wave file %s\n", wavFile);
		return	NULL;
	}

	if (WaveRewind(wavFp, &wavHead) == false)
	{
		wavHead.FormatCategory = -1;
		printf("%s is not a A-law/Mu-law/PCM wave file!\n", wavFile);
		exit(1);
	}
	*header = wavHead;

#ifdef WIN32
	length = filelength(fileno(wavFp)) - 44L;
#else 
	struct stat mybuf;
	if (fstat(fileno(wavFp),&mybuf)== -1)
	{ 
		 printf("Can't get filelength!\n");
	}
	length = mybuf.st_size - 44L;
#endif

	if (length <= 0)	
	{
		printf("It's empty in file %s!\n", wavFile);
		fclose(wavFp);
		return	NULL;
	}
	
	short type, cate;
	cate = wavHead.FormatCategory;
#ifdef PPC
	type = 	(short)((unsigned short)(cate & 0xff00) >> 8);
#else
	type = cate;
#endif
//	printf("%s is format %d filelength is %d\n", wavFile, type, length);
	switch (type)
	{
	case WAVEPCM:
		waveData = new short [length/sizeof(short)];
		numRead = fread(waveData, sizeof(short), length / sizeof(short), wavFp);
		for (i = 0; i < numRead; i++) 
			waveData[i] = SwapInt16(waveData[i]);
		assert(numRead * sizeof(short) == (unsigned long)length);
		*numSamples = length/sizeof(short);
		break;
	case ALAW:	// alaw format
		fseek(wavFp, ANCHOR, SEEK_CUR);
		aulawData = new unsigned char [length];
		numRead = fread(aulawData, sizeof(unsigned char), length-ANCHOR, wavFp);
		assert(numRead  == length-ANCHOR);
		waveData = new short [length];
		for (i = 0; i < length-ANCHOR; i++)
		{
			waveData[i] = alaw2linear(aulawData[i]);
		}
		*numSamples = length;
		delete []	aulawData;
		break;
	case MULAW:	// u-law format
		fseek(wavFp, ANCHOR, SEEK_CUR);
		aulawData = new unsigned char [length];
		numRead = fread(aulawData, sizeof(unsigned char), length-ANCHOR, wavFp);
		assert(numRead  == length-ANCHOR);
		waveData = new short [length];
		for (i = 0; i < length-ANCHOR; i++)
		{
			waveData[i] = ulaw2linear(aulawData[i]);
		}
		*numSamples = length;
		delete []	aulawData;
		break;
	default:
		printf("This wave format is not supported! %s!\n", wavFile);
		exit(1);
		break;
	}
	fclose(wavFp);
//	printf("end of readwave.cpp\n");
	return	waveData;
}
short *ReadPCM(char *file,int *smpCount) 
{ 
    short *wave_data=NULL;
    int max_smpCount=0;
    FILE * rp;
    long length;
    rp=fopen(file,"rb");
    if (rp==NULL) {
        printf("Cannot open  %s file for rb\n",file);
        exit(1);
    }
    fseek(rp, 0L, SEEK_END);
    length = ftell(rp);
//	length = (end-begin+1)*dotsperframe*2;
    *smpCount=length/2;
    if ((*smpCount) > max_smpCount) {                                        
        if(wave_data)                                                         
            free(wave_data);                                             
        wave_data=(short *)malloc(sizeof(short)*(*smpCount));               
        max_smpCount=*smpCount;                                                 
    }                                                                        
    if (wave_data== NULL) {
        printf("cannot new a %ld short  array\n",length);
        exit(1);
    }
    fseek(rp, 0L, SEEK_SET);
    fread(wave_data,sizeof(short ),length/2,rp);
    fclose(rp);
    return wave_data;
}

#define		Frame_Length		320

short*	GetPureSpeech(char *wavFile, int *smpCount) 
{
	short	*wave_data, *pure_speech;
	float	*energy, sum_energy;
	int		frame, i, k, sampleNum, frame_num;
	int		begin, end, final_sample_num;
	short	sample, last_sample, *cross;

	wave_data = ReadPCM(wavFile, &sampleNum);

	frame_num = sampleNum / Frame_Length;

	energy = (float *) malloc( sizeof(float) * frame_num );
	cross  = (short *) malloc( sizeof(short) * frame_num );

	/* get energy of each frame */
	last_sample = 1;
	for (frame = 0; frame < frame_num; frame++)
	{
		sum_energy = 0;
		cross[frame] = 0;

		for (i = 0; i < Frame_Length; i++)
		{
			sample = wave_data[frame * Frame_Length + i];
			sum_energy += sample * sample;

			cross[frame] += (last_sample * sample < 0);
			last_sample = sample;
		}
		energy[frame] = (float)log10(sum_energy/Frame_Length) * 10;
	}

	/* search the front and end of speech */
	k = 0;
	while	(true)
	{
		if ((energy[k] > 50 && cross[k] > 5) ||
			(energy[k] > 45 && cross[k] > 90))
			break;
		if (k >= frame_num - 1)
			break;
		k++;
	}
	if (k == frame_num - 1)
	{
		printf("%s is empty!!!", wavFile);
		k = 0;
	}
	begin = k;
	begin = begin - 2;
	if (begin < 0)
		begin = 0;

	///find end
	k = frame_num - 1;
	while	(true)
	{
		if ((energy[k] > 50 && cross[k] > 5) ||
			(energy[k] > 45 && cross[k] > 90))
			break;
		if (k <= 0)
			break;
		k--;
	}
	if (k == 0)
	{
		printf("%s is empty!!!", wavFile);
		k = frame_num - 1;
	}
	end = k;
	end = end + 2;
	if (end > frame_num - 1)
		end = frame_num - 1;

//	printf("begin = %d    end = %d    frame num = %d\n", begin, end, frame_num);
	
	final_sample_num = (end - begin + 1) * Frame_Length;

	pure_speech = (short *) malloc( sizeof(short) * final_sample_num );

	memcpy( pure_speech, &wave_data[begin], sizeof(short) * final_sample_num );

	*smpCount = final_sample_num;
	free(wave_data);
	free(energy);
	free(cross);

	return	pure_speech;
}

bool WaveRewind(FILE *wav_file, WavHead *WavHead)
{
	char riff[8],wavefmt[8];
	short i;
	rewind(wav_file);
	fread(WavHead,sizeof(struct WavHead),1,wav_file);

	for ( i=0;i<8;i++ )
	{
		riff[i]=WavHead->RIFF[i];
		wavefmt[i]=WavHead->WAVEfmt_[i];
	}
	riff[4]='\0';
	wavefmt[7]='\0';
	if ( strcmp(riff,"RIFF")==0 && strcmp(wavefmt,"WAVEfmt")==0 )
		return	true;  // It is WAV file.
	else
	{
		rewind(wav_file);
		return(false);
	}
}

short *ReadWave(char *wavFile, int *numSamples)
{
	FILE	*wavFp;
	WavHead		wavHead;
	short	*waveData;
	long	numRead;

	wavFp = fopen(wavFile, "rb");
	if (!wavFp)	printf("can't open %s\n", wavFile), exit(1);

	if (WaveRewind(wavFp, &wavHead) == false)
	{
		printf("%s is not a Windows wave file!\n", wavFile);
		exit(1);
	}

	waveData = new short [wavHead.RawDataFileLength/sizeof(short)];
	numRead = fread(waveData, sizeof(short), wavHead.RawDataFileLength / 2, wavFp);
	assert(numRead * sizeof(short) == (unsigned long)wavHead.RawDataFileLength);
	fclose(wavFp);

	*numSamples = wavHead.RawDataFileLength/sizeof(short);
	return	waveData;
}

short *ReadWave(char *wavFile, int *numSamples, WavHead *header)
{
	FILE	*wavFp;
	WavHead		wavHead;
	short	*waveData;
	long	numRead;
	
	wavFp = fopen(wavFile, "rb");
	if (!wavFp)	printf("can't open %s\n", wavFile), exit(1);
	
	if (WaveRewind(wavFp, &wavHead) == false)
	{
		printf("%s is not a Windows wave file!\n", wavFile);
		exit(1);
	}
	*header = wavHead;

	waveData = new short [wavHead.RawDataFileLength/sizeof(short)];
	numRead = fread(waveData, sizeof(short), wavHead.RawDataFileLength / 2, wavFp);
	assert(numRead * sizeof(short) == (unsigned long)wavHead.RawDataFileLength);
	fclose(wavFp);
	
	*numSamples = wavHead.RawDataFileLength/sizeof(short);
	return	waveData;
}

short *ReadAudio(char *wavFile, int *numSamples, WavHead *header)
{
	FILE	*wavFp;
	WavHead		wavHead;
	short	*waveData;
	long	numRead;
	long	numData;

	wavFp = fopen(wavFile, "rb");
	if (!wavFp)	printf("can't open %s\n", wavFile), exit(1);

	if (WaveRewind(wavFp, &wavHead) == false)
	{
		printf("%s is not a Windows wave file!\n", wavFile);
		return NULL;
	}
	*header = wavHead;

	if (wavHead.FileLength - 36L != wavHead.RawDataFileLength)
	{
		printf("FileLength %d - 36 != RawDataFileLength %d in %s!\n", wavHead.FileLength, wavHead.RawDataFileLength, wavFile);
	//	return NULL;
	}
	if (wavHead.FileLength > 20E06)
	{
		printf("%s is too big to read! FileLength is \n", wavFile, wavHead.FileLength);
		return NULL;
	}

	numData = (wavHead.FileLength - 36L) / sizeof(short);

	waveData = new short [numData];
	numRead = fread(waveData, sizeof(short), numData, wavFp);
	assert(numRead == numData);
	fclose(wavFp);
#if 0//1//
	if (wavHead.FileLength - 36L != wavHead.RawDataFileLength)
	{
		WriteWave(wavFile, waveData, numData, 16000, WAVEPCM);
		printf("write %s!\n", wavFile);
		delete waveData;
		return NULL;
	}
	delete waveData;
	return NULL;
#endif

	*numSamples = numData;
	return	waveData;
}

void FillWaveHeader(void *buffer, int raw_wave_len, int sampleRate, WAVE_FORMAT_TYPE type)
{
	WavHead  wavHead;

	strcpy(wavHead.RIFF, "RIFF");
	strcpy(wavHead.WAVEfmt_, "WAVEfmt ");
	wavHead.FileLength = raw_wave_len + 36;
	wavHead.noUse = 16;
	wavHead.FormatCategory = (short)type;
	wavHead.NChannels = 1;
	wavHead.SampleRate = sampleRate;
	switch (type)
	{
	case WAVEPCM:
		wavHead.SampleBytes = sampleRate*2;
		wavHead.BytesPerSample = 2;
		wavHead.NBitsPersample = 16;
		break;

	case ALAW:
		wavHead.SampleBytes = sampleRate;
		wavHead.BytesPerSample = 1;
		wavHead.NBitsPersample = 8;
		break;

	case MULAW:
		wavHead.SampleBytes = sampleRate;
		wavHead.BytesPerSample = 1;
		wavHead.NBitsPersample = 8;
	};
	strcpy(wavHead.data, "data");
	wavHead.RawDataFileLength = raw_wave_len;

	memcpy(buffer, &wavHead, sizeof(WavHead));
}

void WriteWave(char *wavFile, short *waveData, int numSamples, int sampleRate, WAVE_FORMAT_TYPE type)
{
	int		i;
	FILE	*wavFp;
	long	numWrite;
	unsigned char *aulawData;
	WavHead		wavHead;

	wavFp = fopen(wavFile, "wb");
	if (!wavFp)	printf("can't open %s\n", wavFile), exit(1);

	switch (type)
	{
	case WAVEPCM:
		FillWaveHeader(&wavHead, numSamples*sizeof(short), sampleRate, type);
		fwrite(&wavHead, sizeof(WavHead), 1, wavFp);
		numWrite = fwrite(waveData, sizeof(short), numSamples, wavFp);
		break;

	case ALAW:
		FillWaveHeader(&wavHead, numSamples*sizeof(unsigned char), sampleRate, type);
		fwrite(&wavHead, sizeof(WavHead), 1, wavFp);
		aulawData = new unsigned char [numSamples];
		for (i = 0; i < numSamples; i++)
		{
			aulawData[i] = linear2alaw(waveData[i]);
		}
		numWrite = fwrite(aulawData, sizeof(unsigned char), numSamples, wavFp);
		delete []	aulawData;
		break;

	case MULAW:
		FillWaveHeader(&wavHead, numSamples*sizeof(unsigned char), sampleRate, type);
		fwrite(&wavHead, sizeof(WavHead), 1, wavFp);
		aulawData = new unsigned char [numSamples];
		for (i = 0; i < numSamples; i++)
		{
			aulawData[i] = linear2ulaw(waveData[i]);
		}
		numWrite = fwrite(aulawData, sizeof(unsigned char), numSamples, wavFp);
		delete []	aulawData;
		break;

	default:
		printf("can't this kind of wave format %s!\n", wavFile);
		exit(1);
	}
	assert(numWrite == numSamples);
	fclose(wavFp);
}

unsigned char *ReadALawWave(char *wavFile, int *numSamples)
{
	FILE	*wavFp;
	long	numRead;
	WavHead	 wavHead;
	unsigned char *aulawData;
	long	length;

	wavFp = fopen(wavFile, "rb");
	if (!wavFp)	printf("can't open %s\n", wavFile), exit(1);

	if (WaveRewind(wavFp, &wavHead) == false)
	{
		wavHead.FormatCategory = -1;
	}

	length = wavHead.FileLength - 36L;
	aulawData = NULL;
	switch (wavHead.FormatCategory)
	{
	case ALAW:	// alaw format
		fseek(wavFp, ANCHOR, SEEK_CUR);
		length = length - ANCHOR;
		aulawData = new unsigned char [length];
		memset(aulawData, 0, sizeof(unsigned char)*length);
		numRead = fread(aulawData, sizeof(unsigned char), length, wavFp);
		assert(numRead = length);
		break;
	default:
		printf("%s is NOT a alaw wave file!\n", wavFile);
		exit(1);
		break;
	}
	fclose(wavFp);
	*numSamples = length;
	return	aulawData;
}

void WriteALawWave(char *wavFile, unsigned char *aulawData, int numSamples, int sampleRate)
{
	FILE	*wavFp;
	long	numWrite;
	WavHead		wavHead;

	wavFp = fopen(wavFile, "wb");
	if (!wavFp)	printf("can't open %s\n", wavFile), exit(1);

	FillWaveHeader(&wavHead, numSamples*sizeof(unsigned char), sampleRate, ALAW);
	fwrite(&wavHead, sizeof(WavHead), 1, wavFp);
	numWrite = fwrite(aulawData, sizeof(unsigned char), numSamples, wavFp);
	assert(numWrite == numSamples);
	fclose(wavFp);
}

short* ReadALawNoHeaderShortWave(char *wavFile, int *numSamples, WavHead *wavHead)
{
    FILE    *wavFp;
    long    numRead;
    unsigned char *aulawData;
    long    length;
	short	*waveData;

    wavFp = GetFileHandle(wavFile, "rb");
    if (!wavFp)     
	{
		printf("Error: can't open FILE:%s\n", wavFile);
		return	NULL;
	}

    #ifdef WIN32
            length = filelength(fileno(wavFp));
    #else
            struct stat mybuf;
            if (fstat(fileno(wavFp),&mybuf)== -1)
            {
                     printf("Can't get filelength!\n");
            }
            length = mybuf.st_size;
    #endif
    aulawData = NULL;

    aulawData = new unsigned char [length];
    numRead = fread(aulawData, sizeof(unsigned char), length, wavFp);
	fclose(wavFp);
    if (numRead == 0 || numRead != length)
	{
		printf("Error in read %s numRead = %d length = %d!\n", wavFile, numRead, length);
		return	NULL;
	}

	waveData = new short [length * sizeof(short)];
	for (int i = 0; i < length; i++)
	{
		waveData[i] = alaw2linear(aulawData[i]);
	}
	delete aulawData;
	FillWaveHeader(wavHead, length*sizeof(short), 8000, ALAW);
    *numSamples = length;
    return  waveData;
}

unsigned char *ReadALawNoHeaderWave(char *wavFile, int *numSamples)
{
	FILE	*wavFp;
	long	numRead;
	unsigned char *aulawData;
	long	length;

	wavFp = fopen(wavFile, "rb");
	if (!wavFp)	printf("can't open %s\n", wavFile), exit(1);

	#ifdef WIN32
		length = filelength(fileno(wavFp));
	#else 
		struct stat mybuf;
		if (fstat(fileno(wavFp),&mybuf)== -1)
		{ 
			 printf("Can't get filelength!\n");
		}
		length = mybuf.st_size;
	#endif			
	aulawData = NULL;

	aulawData = new unsigned char [length];
	numRead = fread(aulawData, sizeof(unsigned char), length, wavFp);
	assert(numRead = length);

	fclose(wavFp);
	*numSamples = length;
	return	aulawData;
}

void WriteALawNoHeaderWave(char *wavFile, unsigned char *aulawData, int numSamples, int sampleRate)
{
	FILE	*wavFp;
	long	numWrite;

	wavFp = fopen(wavFile, "wb");
	if (!wavFp)	printf("can't open %s\n", wavFile), exit(1);

	numWrite = fwrite(aulawData, sizeof(unsigned char), numSamples, wavFp);
	assert(numWrite == numSamples);
	fclose(wavFp);
}

unsigned char *ReadNoHeaderWave(char *wavFile, int *numSamples)
{
	FILE	*wavFp;
	long	numRead;
	unsigned char *rawData;
	long	length;

	wavFp = fopen(wavFile, "rb");
	if (!wavFp)	printf("can't open %s\n", wavFile), exit(1);

	#ifdef WIN32
		length = filelength(fileno(wavFp));
	#else 
		struct stat mybuf;
		if (fstat(fileno(wavFp),&mybuf)== -1)
		{ 
			 printf("Can't get filelength!\n");
		}
		length = mybuf.st_size;
	#endif			
	rawData = NULL;

	rawData = new unsigned char [length];
	numRead = fread(rawData, sizeof(unsigned char), length, wavFp);
	assert(numRead = length);

	fclose(wavFp);
	*numSamples = length;
	return	rawData;
}

void WriteNoHeaderWave(char *wavFile, unsigned char *rawData, int numSamples)
{
	FILE	*wavFp;
	long	numWrite;

	wavFp = fopen(wavFile, "wb");
	if (!wavFp)	printf("can't open %s\n", wavFile), exit(1);

	numWrite = fwrite(rawData, sizeof(unsigned char), numSamples, wavFp);
	assert(numWrite == numSamples);
	fclose(wavFp);
}

short SwapInt16(short data)
{
#ifdef PPC
	unsigned char hi, lo;
	short	out;
	
	lo = (unsigned char)(0xff & data);
	hi = (unsigned char)((unsigned short)(0xff00 & data) >> 8);
	
	out = (signed short)( ((unsigned short)lo << 8) | (unsigned short)hi);
	
	return out;
#else
	return data;
#endif
}
